import { ERR_OK, ERR_FALSE }  from '@/assets/js/config.js'
import { DEBUG } from '@/store/config.js'
import { urlPrams, dateFormat, timeFormat, randomSoleNumbers, randomNumberString, randomId, randomString, typeCall, timeMinuse, timeToSeconds, convertUrlQueryObject, uncode, zeroize, suffix, removeUrl } from '@/assets/js/util.js'
import request from '@/uni_modules/yingbing-request/js_sdk'
import gb2312 from '@/assets/other/gb2312.js'
import cryptoJS from "@/assets/crypto-js/crypto-js.js"
import base64 from "@/assets/other/base64.js"
import htmlParser from "@/uni_modules/html-parser/js_sdk/index.js"

const HTMLParser = htmlParser//格式化html字符串，用于获取数据
const Base64 = base64//base64加密/解密方法
const CryptoJS = cryptoJS//cryptoJS加密
const Xhr = request.xhr//请求方法
const Http = request.http//请求方法
const GBK = gb2312//字符串转gbk
const HtmlDecode = htmlDecode//解密特殊字符
const DecodeUnicode = uncode//三方字体解码
const DateFormat = dateFormat//日期转化
const TimeFormat = timeFormat//时间转化
const TimeToseconds = timeToSeconds//时间转秒数
const RandomSoleNumbers = randomSoleNumbers//生成随机不重复数字
const RandomNumberString = randomNumberString//生成随机不重复数字字符串
const RandomId = randomId//生成随机id
const RandomString = randomString//生成随机字符串
const TypeCall = typeCall//变量类型
const TimeMinuse = timeMinuse//计算2个时间差的分钟数或者秒数
const Suffix = suffix//获取后缀
const RemoveUrl = removeUrl//移除http域名
const Zeroize = zeroize//补零
const ConvertUrlQueryObject = convertUrlQueryObject//转化url参数为对象
export const statement = [
	'@sync:',
	'@async:',
	'@sel:',
	'@json:',
	'@for:',
	'@map:',
	'@filter:',
	'@find:',
	'@sort:',
	'@replace:',
	'@replaceAll:',
	'@plain:',
	'@split:',
	'@string:',
	'@dateFormat:',
	'@join:',
	'@slice:',
	'@trim:',
	'@have:',
	'@unhave:',
	'@equal:',
	'@unequal:',
	'@eval:',
	'@query:',
	'@match:',
	'@reverse:',
	'@encodeUri:',
	'@decodeUri:',
	'@objectKeys:',
	'@objectArray:',
	'@upper:',
	'@lower:',
	'@response:'
]//声明符

export default class Network {
	constructor (source) {
		this.source = source
		this.timestamp = 0
		this.baseUrl = ''
		this.taskIds = []
		this.responses = [],
		this.logs = []
	}
	destroy () {
		if ( this.taskIds.length > 0 ) {
			request.http.abort(this.taskIds.toString())
			request.xhr.abort(this.taskIds.toString())
		}
		this.timestamp = 0
		this.baseUrl = ''
		this.taskIds = []
		this.responses = []
		this.logs = []
	}
	log (text, result, replace = false) {
		const debug = uni.getStorageSync(DEBUG)
		if ( debug ) {
			if ( replace ) this.logs[this.logs.length - 1] = {text, result}
			else this.logs.push({ text, result })
		}
	}
	clearLog () {
		this.logs = []
	}
	$request ({url, params, header, method, timeout, device, charset, response, cacheEfficiency}) {
		return new Promise(async (resolve, reject) => {
			this.log('请求链接：' + (url || null))
			const timestamp = typeof cacheEfficiency == 'number' ? cacheEfficiency : typeof this.source.cacheEfficiency == 'number' ? this.source.cacheEfficiency : 10000
			this.responses = this.responses.filter(rep => new Date().getTime() - rep.timestamp < timestamp)//默认缓存10秒有效
			const index = timestamp == 0 ? -1 : this.responses.findIndex(rep => (rep.url || '') == urlPrams(url || '', params || {}))
			if ( index > -1 ) {
				try{
					const content = this.responses[index].content
					this.log('获取到缓存', content)
					if ( response ) resolve(await this.$text(response, content))
					else resolve(content)
				}catch(e){
					reject(e)
				}
			} else {
				const taskId = randomId()
				this.taskIds.push(taskId)
				const requestUrl = url || ''
				if ( requestUrl.slice(0, 4) != 'http' ) this.log('获取基础域名')
				const baseUrl = requestUrl.slice(0, 4) == 'http' ? '' : await this.getBaseUrl()
				if ( requestUrl.slice(0, 4) != 'http' ) this.log('获取基础域名：' + baseUrl, null, true)
				const requestParams = params || {}
				const requestHeader = header || {}
				const requestMethod = method || 'get'
				const requestCharset = charset || ''
				const requestDevice = device || '电脑'
				const requestTimeout = timeout || this.source.timeout || 10000//请求超时时间默认为10秒
				this.log('开始正式请求', {
					requestUrl: baseUrl + requestUrl,
					requestParams,
					requestHeader,
					requestMethod,
					requestCharset,
					requestDevice,
					requestTimeout
				})
				const realheader = Object.assign({}, {
					Referer: baseUrl
				}, requestHeader, {
					Charset: requestCharset == 'GBK' ? 'gbk' : 'utf-8'
				})
				realheader[requestCharset == 'GBK' ? 'UserAgent' : 'user-agent'] = requestDevice == '手机' ? 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36'
				request[requestCharset == 'GBK' ? 'xhr' : 'http'][requestMethod.toLowerCase()](baseUrl + requestUrl, {
					taskId: taskId,
					params: requestParams,
					timeout: requestTimeout,
					mimeType: requestHeader.mimeType || (requestCharset == 'GBK' ? 'text/html;charset=gb2312' : undefined),
					header: realheader
				}).then(async res => {
					this.taskIds = this.taskIds.filter(id => id != taskId)
					const content = typeof res.data == 'string' ? htmlDecode(res.data) : res.data
					this.log('请求成功', content)
					//记录缓存
					this.responses.push({
						timestamp: new Date().getTime(),
						url: urlPrams(url, params),
						content: content
					})
					const newContent = response ? await this.$text(response, content) : content
					if ( response ) this.log('处理response编译' + response + '成功', newContent)
					resolve(newContent)
				}).catch(err => {
					this.log('请求失败：' + JSON.stringify(err))
					this.taskIds = this.taskIds.filter(id => id != taskId)
					reject(err)
				})
			}
		})
	}
	$fnc (params) {
		const { page, keyword } = params
		const Fnc = {}
		if ( this.source.fnc ) {
			const fnc = this.source.fnc || {}
			Object.keys(fnc).forEach(key => {
				Fnc[key] = typeof fnc[key] == 'string' ? eval('(' + fnc[key] + ')') : eval('(' + fnc[key].toString() + ')' )
			})
		}
		return Fnc
	}
	$pre (rule) {
		return rule.indexOf(':') > -1 ? rule.slice(0, rule.indexOf(':')+1) : ''
	}
	$eval (text, params) {
		const globalData = this.source.globalData || {}
		const globalMethod = {}
		let value = ''
		try{
			value = eval("( function () { return " + text + "})")()
		}catch(e){
			value = ''
		}
		return value
	}
	$extract (inputString, patterns) {
		try{
			return extractPattern(inputString, patterns)
		}catch(e){
			return null
		}
	}
	async $list (resource, content) {
		this.log('编译 ' + JSON.stringify(resource) + ' 执行list函数')
		const list = resource.list ? await this.$text(resource.list, content, content) : [content]
		if ( resource.list ) this.log('编译 ' + resource.list + ' 执行value函数', list)
		if ( resource.filter ) {
			for ( let i = 0; i < list.length; i++ ) {
				const value = await this.$text(resource.filter, list[i], content)
				if ( !value ) list.splice(i, 1)
			}
			this.log('编译 ' + resource.filter + ' 执行filter函数', list)
		}
		const results = []
		for ( let i = 0; i < list.length; i++) {
			const item = await this.$object(Object.assign({}, resource, {list: undefined, filter: undefined}), list[i], content)
			results.push(
				Object.assign({}, item, {
					sourceId: this.source.id,
					sourceName: this.source.name
				})
			)
		}
		const result = resource.list ? results : (results[0] || null)
		this.log('编译 ' + JSON.stringify(resource) + ' 结束', result)
		return result
	}
	async $object(obj, content, response) {
		return await this.traverseAndModify(obj, value => this.$text(value, content, response), content, response)
	}
	//遍历无限层级对象，并格式化数据
	async traverseAndModify(obj, modify, content, response) {
	    for (let key in obj) {
			if ( obj[key] ) {
				if (typeof obj[key] === 'object') {
					// 如果属性值是对象，则递归遍历
					if ( obj[key].list ) obj[key] = await this.$list(obj[key], content, response); //是否有list属性，有则建立新的数组遍历
					else await this.traverseAndModify(obj[key], modify, content, response)//否则递归遍历对象 
				} else obj[key] = await modify(obj[key]) // 调用修改函数
			}
	    }
		return obj
	}
	async $text (rule, content, response) {
		rule = rule.toString()
		const newRule = await this.judgeFormat(rule, content, response || content)
		const pre = this.$pre(newRule)
		return statement.indexOf(pre) == -1 ? this.textFormat(newRule, content, response || content) : this.valueFormat(newRule, content, response || content)
	}
	dataHandle (data, params = {}) {
		let str = JSON.stringify(data)
		const binds = str.match(/{{[^}}]+}}/g) || []
		binds.forEach(bind => {
			const handle = bind.match(/{{*([\s\S]*?)}}/)[1]
			if ( typeof params[handle] != 'undefined' ) str = str.replace(bind, params[handle])
			else str = str.replace(bind, this.$eval(handle, params))
		})
		return JSON.parse(str)
	}
	staticDataHandle (staticData, params = {}) {
		const data = this.dataHandle(staticData, params)
		const arr = typeCall(data) == 'Array' ? data : [data]
		const url = params.routeUrl
		const newArr = arr.map(item => Object.assign({}, { isAdult: this.source.isAdult || 0 }, item, {
				sourceId: this.source.id,
				sourceName: this.source.name,
				isAdult: this.source.isAdult || 0,
			}, url ? {url, uniqueId: url} : {})
		)
		return typeCall(data) == 'Array' ? newArr : newArr[0]
	}
	requestHandle (request, params = {}) {
		return this.dataHandle(request, params)
	}
	getUniqueId (request) {
		return urlPrams(request.url || '', request.params || {})
	}
	async getShareUrl (request) {
		const baseUrl = await this.getBaseUrl()
		return urlPrams((baseUrl + request.url) || '', request.params || {})
	}
	async getBaseUrl () {
		try{
			const dynamic = this.source.dynamic
			if ( !dynamic ) return this.source.href
			if ( new Date().getTime() - this.timestamp < 60 && this.baseUrl ) return this.baseUrl
			const content = await this.$request(dynamic)
			const result = await this.$text(dynamic.result, content)
			return result
		}catch(e){
			return this.source.href
		}
	}
	throwerror (rule, err) {
		this.errors.push(rule + '：' + err.message)
	}
	//判断条件
	async judgeFormat (rule, content, response) {
		try{
			const ifregex = new RegExp(/<if>*([\s\S]*?)<\/if>/, 'g');
			const elseifregex = new RegExp(/<elseif>*([\s\S]*?)<\/elseif>/, 'g');
			const elseregex = new RegExp(/<else(?!\w)>*([\s\S]*?)<\/else>/, 'g');
			const thenregex = new RegExp(/<then>*([\s\S]*?)<\/then>/, 'g');
			let match, result = ''
			const ifs = [], elseifs = [], thens = [], elses = []
			while ((match = ifregex.exec(rule))) {//匹配if标签
			  ifs.push({
				  index: match.index,
				  text: match[0]
			  });
			}
			while ((match = elseifregex.exec(rule))) {//匹配elseif标签
			  elseifs.push({
				  index: match.index,
				  text: match[0]
			  });
			}
			while ((match = elseregex.exec(rule))) {//匹配else标签
			  elses.push({
				  index: match.index,
				  text: match[0]
			  });
			}
			while ((match = thenregex.exec(rule))) {//匹配then标签
			  thens.push({
				  index: match.index,
				  text: match[0]
			  });
			}
			const arr = ifs.concat(elseifs).concat(elses).concat(thens).sort((a,b) => a.index - b.index)//合并标签并排序
			const newArr = []
			for ( let i = 0; i < arr.length; i++ ) {
				const text = arr[i].text
				if ( text.indexOf('<if>') > -1 ) newArr.push([])
				newArr[newArr.length-1].push(text)
			}
			for ( let i = 0; i < newArr.length; i++ ) {
				const items = newArr[i]
				for ( let j = 0; j < items.length; j++ ) {
					if ( items[j].indexOf('<if>') > -1 ) {
						const text = items[j].match(/<if>*([\s\S]*?)<\/if>/)[1]
						if ( await this.valueFormat(text, content, response) ) {
							result += items[j+1].indexOf('<then>') > -1 ? items[j+1].match(/<then>*([\s\S]*?)<\/then>/)[1] : ''
							break
						}
					}
					if ( items[j].indexOf('<elseif>') > -1 ) {
						const text = items[j].match(/<elseif>*([\s\S]*?)<\/elseif>/)[1]
						if ( await this.valueFormat(text, content, response) ) {
							result += items[j+1].indexOf('<then>') > -1 ? items[j+1].match(/<then>*([\s\S]*?)<\/then>/)[1] : ''
							break
						}
					}
					if ( items[j].indexOf('<else>') > -1 ) {
						result += items[j].match(/<else>*([\s\S]*?)<\/else>/)[1]
						break
					}
				}
			}
			return newArr.length > 0 ? result : rule
		}catch(e){
			this.log('编译 ' + rule + ' 执行条件语句函数失败：' + e.toString())
			return ''
		}
	}
	async textFormat (rule, content, response) {
		try{
			let text = rule.replace('@text:', '')
			let arr = text.match(/<js>*([\s\S]*?)<\/js>/g) || []
			for ( let i=0;i<arr.length;i++ ) {
				let value = arr[i].match(/<js>*([\s\S]*?)<\/js>/)[1]
				text = text.replace(arr[i], await this.valueFormat(value, content, response))
			}
			text = escapeFormat(text) || ''
			return text
		}catch(e){
			this.log('编译 ' + rule + ' 执行文本函数失败：' + e.toString())
			return ''
		}
	}
	
	async valueFormat (rules, content, response) {
		let result = content
		const arr = this.$extract(rules, statement)
		for ( let i = 0; i < arr.length; i++ ) {
			const rule = escapeFormat(arr[i].data)
			const pre = arr[i].type
			if ( pre == '@response:' ) {
				result = response
			} else if ( pre == '@sync:' ) {
				result = this.syncFormat(result, rule)
			} else if ( pre == '@async:' ) {
				result = await this.asyncFormat(result, rule)
			} else if ( pre == '@json:' ) {
				result = this.jsonFormat(result, rule)
			} else if ( pre == '@sel:' ) {
				result = this.selFormat(result, rule)
			} else if ( pre == '@for:' ) {
				result = this.forFormat(result, rule)
			} else if ( pre == '@map:' ) {
				result = this.mapFormat(result, rule)
			} else if ( pre == '@filter:' ) {
				result = this.filterFormat(result, rule)
			} else if ( pre == '@replace:' ) {
				result = this.replaceFormat(result, rule)
			} else if ( pre == '@replaceAll:' ) {
				result = this.replaceAllFormat(result, rule)
			} else if ( pre == '@plain:' ) {
				result = this.plainFormat(result, rule)
			} else if ( pre == '@split:' ) {
				result = this.splitFormat(result, rule)
			} else if ( pre == '@find:' ) {
				result = this.findFormat(result, rule)
			} else if ( pre == '@sort:' ) {
				result = this.sortFormat(result, rule)
			} else if ( pre == '@trim:' ) {
				result = this.trimFormat(result, rule)
			} else if ( pre == '@have:' ) {
				result = this.haveFormat(result, rule)
			} else if ( pre == '@unhave:' ) {
				result = this.unhaveFormat(result, rule)
			} else if ( pre == '@equal:' ) {
				result = this.equalFormat(result, rule)
			} else if ( pre == '@unequal:' ) {
				result = this.unequalFormat(result, rule)
			} else if ( pre == '@eval:' ) {
				result = this.evalFormat(result, rule)
			} else if ( pre == '@query:' ) {
				result = this.queryFormat(result, rule)
			} else if ( pre == '@match:' ) {
				result = this.matchFormat(result, rule)
			} else if ( pre == '@string:' ) {
				result = this.stringFormat(result, rule)
			} else if ( pre == '@dateFormat:' ) {
				result = this.dateFormatFormat(result, rule)
			} else if ( pre == '@join:' ) {
				result = this.joinFormat(result, rule)
			} else if ( pre == '@slice:' ) {
				result = this.sliceFormat(result, rule)
			} else if ( pre == '@reverse:' ) {
				result = this.reverseFormat(result, rule)
			} else if ( pre == '@encodeUri:' ) {
				result = this.encodeUriFormat(result, rule)
			} else if ( pre == '@decodeUri:' ) {
				result = this.decodeUriFormat(result, rule)
			} else if ( pre == '@objectKeys:' ) {
				result = this.objectKeysFormat(result, rule)
			} else if ( pre == '@objectArray:' ) {
				result = this.objectArrayFormat(result, rule)
			} else if ( pre == '@upper:' ) {
				result = this.upperFormat(result, rule)
			} else if ( pre == '@lower:' ) {
				result = this.lowerFormat(result, rule)
			} else {
				result = result + pre + rule
			}
		}
		return result
	}
	
	syncFormat (lastResult, rule) {
		try{
			const handle = eval(
				"( function () {" + rule + " } )"
			)
			return handle()
		}catch(e){
			this.log('编译 ' + rule + ' 执行同步方法函数失败：' + e.toString())
			return ''
		}
	}
	
	async asyncFormat (lastResult, rule) {
		try{
			const handle = eval(
				"( async function () {" + rule + "} )"
			)
			return await handle()
		}catch(e){
			this.log('编译 ' + rule + ' 执行异步方法函数失败：' + e.toString())
			return ''
		}
	}
	
	jsonFormat (lastResult, rule) {
		try{
			let result = lastResult
			const arr = rule.split('.')
			for ( let i = 0;i < arr.length;i++ ) {
				const downIndex = arr[i].match(/\[([^\]]+)\]/)
				const key = downIndex ? arr[i].replace(downIndex[0], '') : arr[i]
				result = key ? result[key] : result
				result = downIndex ? result[downIndex[1]] : result
			}
			return result
		}catch(e){
			this.log('编译 ' + rule + ' 执行json函数失败：' + e.toString())
			return ''
		}
	}
	
	selFormat (lastResult, rule) {
		try{
			const arr = rule.split('>>')
			let index = 0
			let contents = typeCall(lastResult) == 'Array' ? lastResult : [lastResult]
			let isArray = typeCall(lastResult) == 'Array'//返回数据是否是数组
			while ( index < arr.length ) {
				const ands = arr[index].split('&&')//是否查询多个指定元素
				let results = []
				ands.forEach(and => {
					const attrs = and.split('.')
					const downIndex = attrs[1] ? attrs[1].match(/\[([^\]]+)\]/) : null
					contents.forEach(content => {
						const document = typeCall(content) == 'String' ? new HTMLParser(content.trim()) : new HTMLParser(content.outerHTML.trim())
						if ( attrs[0] == 'class' ) {
							if ( downIndex ) results.push(document.getElementsByClassName(attrs[1].replace(downIndex[0], '') )[downIndex[1]])
							else {
								results = results.concat(document.getElementsByClassName(attrs[1])),
								isArray = true
							}
						} else if ( attrs[0] == 'id' ) {
							results = results.concat(document.getElementById(attrs[1]))
						} else if ( attrs[0] == 'tag' ) {
							if ( downIndex ) results.push(document.getElementsByTagName(attrs[1].replace(downIndex[0], '') )[downIndex[1]])
							else {
								results = results.concat(document.getElementsByTagName(attrs[1]))
								isArray = true
							}
						} else if ( attrs[0] == 'attr' ) {
							results.push(content.attributes[attrs[1]])
						} else if ( attrs[0] == 'html' ) {
							results.push(content.outerHTML.trim())
						} else if ( attrs[0] == 'content' ) {
							results.push(content.innerHTML.trim())
						} else if ( attrs[0] == 'text' ) {
							results.push(content.innerHTML.trim().replace(/<[^>]+>/g, '').trim().replace(/\s/g, '').replace(/\n/g, ' '))
						}
					})
				})
				contents = results
				index++
			}
			return isArray ? contents : contents.length > 1 ? contents : (contents[0] || '')
		}catch(e){
			this.log('编译 ' + rule + ' 执行选择器函数失败：' + e.toString())
			return ''
		}
		// try{
		// 	let result = lastResult
		// 	let arr = rule.split('>>')
		// 	for ( let i =0; i < arr.length; i++ ) {
		// 		const attrs = arr[i].split('.')
		// 		const downIndex = attrs[1] ? attrs[1].match(/\[([^\]]+)\]/) : null
		// 		result = typeCall(result) == 'Array' ? result[0] : result
		// 		const document = typeCall(result) == 'String' ? new HTMLParser(result.trim()) : new HTMLParser(result.outerHTML.trim())
		// 		if ( attrs[0] == 'class' ) {
		// 			result = downIndex ? document.getElementsByClassName(attrs[1].replace(downIndex[0], '') )[downIndex[1]] : document.getElementsByClassName(attrs[1])
		// 		} else if ( attrs[0] == 'id' ) {
		// 			result = document.getElementById(attrs[1])
		// 		} else if ( attrs[0] == 'tag' ) {
		// 			result = downIndex ? document.getElementsByTagName(attrs[1].replace(downIndex[0], '') )[downIndex[1]] : document.getElementsByTagName(attrs[1])
		// 		} else if ( attrs[0] == 'attr' ) {
		// 			result = result.attributes[attrs[1]]
		// 		} else if ( attrs[0] == 'html' ) {
		// 			result = result.outerHTML.trim()
		// 		} else if ( attrs[0] == 'content' ) {
		// 			result = result.innerHTML.trim()
		// 		} else if ( attrs[0] == 'text' ) {
		// 			result = result.innerHTML.trim()
		// 			result = result.replace(/<[^>]+>/g, '').trim()
		// 		}
		// 	}
		// 	return result
		// }catch(e){
		// 	console.log('e', e);
		// 	this.throwerror(rule, e)
		// 	return ''
		// }
	}
	
	forFormat (lastResult, rule) {
		try{
			const handle = eval("( function () { var result = []; lastResult.forEach((item, key) => {" + rule +  "}); return result } )")
			return handle()
		}catch(e){
			this.log('编译 ' + rule + ' 执行for函数失败：' + e.toString())
			return ''
		}
	}
	
	mapFormat (lastResult, rule) {
		try{
			const handle = eval("( function () { return lastResult.map((item, key) =>" + rule +  ") } )")
			return handle()
		}catch(e){
			this.log('编译 ' + rule + ' 执行map函数失败：' + e.toString())
			return ''
		}
	}
	
	filterFormat (lastResult, rule) {
		try{
			const handle = eval("( function () { return lastResult.filter((item, key) =>" + rule +  ") } )")
			return handle()
		}catch(e){
			this.log('编译 ' + rule + ' 执行filter函数失败：' + e.toString())
			return ''
		}
	}
	
	replaceFormat (lastResult, rule) {
		try{
			const arr = rule.split('>>')
			if ( arr.length > 0 ) {
				return lastResult.replace(arr[0], arr[1] || '')
			} else { return lastResult }
		}catch(e){
			this.log('编译 ' + rule + ' 执行replace函数失败：' + e.toString())
			return ''
		}
	}
	
	replaceAllFormat (lastResult, rule) {
		try{
			const arr = rule.split('>>')
			if ( arr.length > 0 ) {
				return lastResult.replace(eval(`/${arr[0]}/g`), arr[1] || '')
			} else { return lastResult }
		}catch(e){
			this.log('编译 ' + rule + ' 执行replaceAll函数失败：' + e.toString())
			return ''
		}
	}
	
	plainFormat (lastResult, rule) {
		try{
			return lastResult.trim().replace(/<[^>]+>/g, '').trim().replace(/\s/g, '').replace(/\n/g, ' ')
		}catch(e){
			this.log('编译 ' + rule + ' 执行plain函数失败：' + e.toString())
			return ''
		}
	}
	
	splitFormat (lastResult, rule) {
		try{
			const arr = rule.split('>>')
			const split = arr[0]
			return arr[1] ? lastResult.split(split)[arr[1]] : lastResult.split(split)
		}catch(e){
			this.log('编译 ' + rule + ' 执行split函数失败：' + e.toString())
			return ''
		}
	}
	
	findFormat (lastResult, rule) {
		try{
			const handle = eval("( function () { var index = lastResult.findIndex((item, key) =>" + rule +  "); return index > -1 ? lastResult[index] : '' } )")
			return handle()
		}catch(e){
			this.log('编译 ' + rule + ' 执行find函数失败：' + e.toString())
			return ''
		}
	}
	
	sortFormat (lastResult, rule) {
		try{
			const handle = eval("( function () { lastResult.sort((a, b) =>" + rule +  "); return lastResult } )")
			return handle()
		}catch(e){
			this.log('编译 ' + rule + ' 执行sort函数失败：' + e.toString())
			return ''
		}
	}
	
	trimFormat (lastResult, rule) {
		try{
			return lastResult.trim()
		}catch(e){
			this.log('编译 ' + rule + ' 执行trim函数失败：' + e.toString())
			return ''
		}
	}
	
	haveFormat (lastResult, rule) {
		try{
			return lastResult.indexOf(rule) > -1
		}catch(e){
			this.log('编译 ' + rule + ' 执行have函数失败：' + e.toString())
			return false
		}
	}
	
	unhaveFormat (lastResult, rule) {
		try{
			return lastResult.indexOf(rule) == -1
		}catch(e){
			this.log('编译 ' + rule + ' 执行unhave函数失败：' + e.toString())
			return false
		}
	}
	
	equalFormat (lastResult, rule) {
		try{
			return lastResult == rule
		}catch(e){
			this.log('编译 ' + rule + ' 执行equal函数失败：' + e.toString())
			return false
		}
	}
	
	unequalFormat (lastResult, rule) {
		try{
			return lastResult != rule
		}catch(e){
			this.log('编译 ' + rule + ' 执行unequal函数失败：' + e.toString())
			return false
		}
	}
	
	evalFormat (lastResult, rule) {
		try{
			const handle = rule == 'function' ? eval( "( function () { return " + lastResult + "} )" ) : eval( "(" + lastResult + ")" )
			return typeof handle == "function" ? handle() : handle
		}catch(e){
			this.log('编译 ' + rule + ' 执行eval函数失败：' + e.toString())
			return ''
		}
	}
	
	queryFormat (lastResult, rule) {
		try{
			const index = lastResult.indexOf('?')
			const search = index > -1 ? lastResult.substring(index+1) : lastResult
			const vars = search.split('&')
			const obj = {}
			for (let i=0;i<vars.length;i++) {
			    let pair = vars[i].split("=");
				obj[pair[0]] = pair[1]
			}
			return obj;
		}catch(e){
			this.log('编译 ' + rule + ' 执行query函数失败：' + e.toString())
			return ''
		}
	}
	
	matchFormat (lastResult, rule) {
		try{
			const arr = rule.split('>>')
			const match = lastResult.match(eval(`/${arr[0]}*([\\s\\S]*?)${arr[1]}/`) )
			return arr[2] ? match[arr[2]] : match
		}catch(e){
			this.log('编译 ' + rule + ' 执行match函数失败：' + e.toString())
			return ''
		}
	}
	
	stringFormat (lastResult, rule) {
		try{
			let binary = rule || 10
			return lastResult.toString(binary)
		}catch(e){
			this.log('编译 ' + rule + ' 执行string函数失败：' + e.toString())
			return ''
		}
	}
	
	dateFormatFormat (lastResult, rule) {
		try{
			const formats = rule || 'yyyy-mm-dd hh:mm:ss'
			return dateFormat(lastResult, formats)
		}catch(e){
			this.log('编译 ' + rule + ' 执行dateFormat函数失败：' + e.toString())
			return ''
		}
	}
	
	joinFormat (lastResult, rule) {
		try{
			const binary = rule || ','
			return lastResult.join(binary)
		}catch(e){
			this.log('编译 ' + rule + ' 执行join函数失败：' + e.toString())
			return ''
		}
	}
	
	sliceFormat (lastResult, rule) {
		try{
			const arr = rule.split('>>')
			return arr.length > 1 ? lastResult.slice(arr[0], arr[1]) : lastResult.slice(arr[0])
		}catch(e){
			this.log('编译 ' + rule + ' 执行join函数失败：' + e.toString())
			return ''
		}
	}
	
	reverseFormat (lastResult, rule) {
		try{
			return lastResult.reverse()
		}catch(e){
			this.log('编译 ' + rule + ' 执行reverse函数失败：' + e.toString())
			return ''
		}
	}
	
	encodeUriFormat (lastResult, rule) {
		try{
			return encodeURIComponent(lastResult)
		}catch(e){
			this.log('编译 ' + rule + ' 执行encodeUri函数失败：' + e.toString())
			return ''
		}
	}
	
	decodeUriFormat (lastResult, rule) {
		try{
			return decodeURIComponent(lastResult)
		}catch(e){
			this.log('编译 ' + rule + ' 执行decodeUri函数失败：' + e.toString())
			return ''
		}
	}
	
	objectKeysFormat (lastResult, rule) {
		try{
			return Object.keys(lastResult)
		}catch(e){
			this.log('编译 ' + rule + ' 执行objectKeys函数失败：' + e.toString())
			return ''
		}
	}
	
	objectArrayFormat (lastResult, rule) {
		try{
			const keys = Object.keys(lastResult)
			let arr = []
			keys.forEach(key => arr = arr.concat(lastResult[key]))
			return arr
		}catch(e){
			this.log('编译 ' + rule + ' 执行objectArray函数失败：' + e.toString())
			return ''
		}
	}
	
	upperFormat (lastResult, rule) {
		try{
			return lastResult.toUpperCase()
		}catch(e){
			this.log('编译 ' + rule + ' 执行upper函数失败：' + e.toString())
			return ''
		}
	}
	
	lowerFormat (lastResult, rule) {
		try{
			return lastResult.toLowerCase()
		}catch(e){
			this.log('编译 ' + rule + ' 执行lower函数失败：' + e.toString())
			return ''
		}
	}
}

//转义html特殊字符
function htmlDecode (str) {
	let s = ""
	if (str.length == 0) return ""
	// s = str.replace(/&#x/g, "\\u")
	s = str.replace(/&#58;/g, ":")
	s = s.replace(/&#32;/g, " ")
	s = s.replace(/&#33;/g, "!")
	s = s.replace(/&#34;/g, '"')
	s = s.replace(/&#35;/g, "#")
	s = s.replace(/&#36;/g, "$")
	s = s.replace(/&#37;/g, "%")
	s = s.replace(/&#38;/g, "&")
	s = s.replace(/&#39;/g, "'")
	s = s.replace(/&#40;/g, "(")
	s = s.replace(/&#41;/g, ")")
	s = s.replace(/&#42;/g, "*")
	s = s.replace(/&#43;/g, "+")
	s = s.replace(/&#44;/g, ",")
	s = s.replace(/&#45;/g, "-")
	s = s.replace(/&#46;/g, ".")
	s = s.replace(/&#47;/g, "/")
	s = s.replace(/&#13;/g, "\n")
	s = s.replace(/<br\/>/g, "\n")
	s = s.replace(/<br \/>/g, "\n")
	s = s.replace(/<br>/g, "\n")
	s = s.replace(/&amp;/g, "")
	s = s.replace(/&nbsp;/g, " ")
	s = s.replace(/&#8211;/g, "–")
	s = s.replace(/#65279;/g, "")
	s = s.replace(/&hellip;/g, '...')
	s = s.replace(/&mdash;/g, '—')
	s = s.replace(/&ldquo;/g, "“")
	s = s.replace(/&rdquo;/g, "”")
	s = s.replace(/&middot;/g, ".")
	s = s.replace(/&iexcl;/g, "¡")
	s = s.replace(/&cent;/g, "¢")
	s = s.replace(/&pound;/g, "£")
	s = s.replace(/&curren;/g, "¤")
	s = s.replace(/&yen;/g, "¥")
	s = s.replace(/&sect;/g, "§")
	s = s.replace(/&uml;/g, "¨")
	s = s.replace(/&copy;/g, "©")
	s = s.replace(/&ordf;/g, "ª")
	s = s.replace(/&laquo;/g, "«")
	s = s.replace(/&not;/g, "¬")
	s = s.replace(/&reg;/g, "®")
	s = s.replace(/&macr;/g, "¯")
	s = s.replace(/&deg;/g, "°")
	s = s.replace(/&plusmn;/g, "±")
	s = s.replace(/&acute;/g, "´")
	s = s.replace(/&micro;/g, "µ")
	s = s.replace(/&para;/g, "¶")
	s = s.replace(/&middot;/g, "·")
	s = s.replace(/&cedil;/g, "¸")
	s = s.replace(/&ordm;/g, "º")
	s = s.replace(/&raquo;/g, "»")
	s = s.replace(/&iquest;/g, "¿")
	s = s.replace(/&Agrave;/g, "À")
	s = s.replace(/&Aacute;/g, "Á")
	s = s.replace(/&Acirc;/g, "Â")
	s = s.replace(/&Atilde;/g, "Ã")
	s = s.replace(/&Auml;/g, "Ä")
	s = s.replace(/&Aring;/g, "Å")
	s = s.replace(/&AElig;/g, "Æ")
	s = s.replace(/&Ccedil;/g, 'Ç')
	s = s.replace(/&Egrave;/g, "È")
	s = s.replace(/&Eacute;/g, "É")
	s = s.replace(/&Ecirc;/g, "Ê")
	s = s.replace(/&Euml;/g, "Ë")
	s = s.replace(/&Igrave;/g, "Ì")
	s = s.replace(/&Iacute;/g, "Í")
	s = s.replace(/&Icirc;/g, "Î")
	s = s.replace(/&Iuml;/g, "Ï")
	s = s.replace(/&Ntilde;/g, "Ñ")
	s = s.replace(/&Ograve;/g, "Ò")
	s = s.replace(/&Oacute;/g, "Ó")
	s = s.replace(/&Ocirc;/g, "Ô")
	s = s.replace(/&Otilde;/g, "Õ")
	s = s.replace(/&Ouml;/g, "Ö")
	s = s.replace(/&Oslash;/g, "Ø")
	s = s.replace(/&Ugrave;/g, "Ù")
	s = s.replace(/&Uacute;/g, "Ú")
	s = s.replace(/&Ucirc;/g, "Û")
	s = s.replace(/&Uuml;/g, "Ü")
	s = s.replace(/&szlig;/g, "ß")
	s = s.replace(/&agrave;/g, "à")
	s = s.replace(/&aacute;/g, "á")
	s = s.replace(/&acirc;/g, "â")
	s = s.replace(/&atilde;/g, "ã")
	s = s.replace(/&auml;/g, "ä")
	s = s.replace(/&aring;/g, "å")
	s = s.replace(/&aelig;/g, "æ")
	s = s.replace(/&ccedil;/g, "ç")
	s = s.replace(/&egrave;/g, "è")
	s = s.replace(/&eacute;/g, "é")
	s = s.replace(/&ecirc;/g, "ê")
	s = s.replace(/&euml;/g, "ë")
	s = s.replace(/&igrave;/g, "ì")
	s = s.replace(/&iacute;/g, "í")
	s = s.replace(/&icirc;/g, "î")
	s = s.replace(/&iuml;/g, "ï")
	s = s.replace(/&ntilde;/g, "ñ")
	s = s.replace(/&ograve;/g, "ò")
	s = s.replace(/&oacute;/g, "ó")
	s = s.replace(/&ocirc;/g, "ô")
	s = s.replace(/&otilde;/g, "õ")
	s = s.replace(/&ouml;/g, "ö")
	s = s.replace(/&divide;/g, "÷")
	s = s.replace(/&oslash;/g, "ø")
	s = s.replace(/&ugrave;/g, "ù")
	s = s.replace(/&uacute;/g, "ú")
	s = s.replace(/&ucirc;/g, "û")
	s = s.replace(/&uuml;/g, "ü")
	s = s.replace(/&yuml;/g, "ÿ")
	return s
}

//转义字符替换
export function escapeFormat (str) {
	str = str.replace(/&es;/g, '\\')
	str = str.replace(/&wrap;/g, '\n')
	str = str.replace(/&nbsp;/g, ' ')
	str = str.replace(/&tabu;/g, '\t')
	str = str.replace(/&quot;/g, '\"')
	str = str.replace(/&apos;/g, "\'")
	str = str.replace(/&lt;/g, "<")
	str = str.replace(/&gt;/g, ">")
	str = str.replace(/&oe;/g, "{")
	str = str.replace(/&ce;/g, "}")
	return str
}

//匹配定义符和内容
export function extractPattern (inputString, patterns) {
	const extractedData = [];
	const patternsSync = inputString.match(eval(`/${patterns.join('|')}/g`)) || []
	patternsSync.forEach((pattern, key) => {
		let matches
	    const regex = new RegExp(`(${pattern})([\\s\\S]*?)(${patterns.join('|')}|$)`);
		const match = regex.exec(inputString)
		if ( match ) {
			matches = { type: match[1], data: match[2] }
			extractedData.push(matches);
			inputString = inputString.replace(matches.type + matches.data, '')
		}
	});
	return extractedData
}

export async function getClassification (req, rule) {
	const list = []
	const arr = rule.split('$:')
	for ( let i = 0; i < arr.length; i++ ) {
		const item = arr[i]
		let child = []
		const title = item.split('?:').length > 1 ? item.split('?:')[0] : ''
		const urlRule = item.split('?:').length > 1 ? item.split('?:')[1] : item
		const preIndex = urlRule.indexOf(':')
		const pre = urlRule.slice(0, preIndex+1)
		if ( pre == '@sync:' ) {
			try{
				const handle = eval('( function () {' + escapeFormat(urlRule.replace(pre, '')) + '} )')
				child = handle() || []
			}catch(e){
				child = []
				uni.showToast({
					title: e.toString(),
					icon:'none',
					duration: 5000
				})
			}
		} else if ( pre == '@async:' ) {
			try{
				const handle = eval('( async function () {' + escapeFormat(urlRule.replace(pre, '')) + '} )')
				child = await handle() || []
			}catch(e){
				child = []
				uni.showToast({
					title: e.toString(),
					icon:'none',
					duration: 5000
				})
			}
		} else {
			let urls = urlRule.split('+:')
			urls.forEach(url => {
				child.push({
					label: url.split('::')[0],
					value: url.split('::')[1]
				})
			})
		}
		list.push({
			title: title,
			child,
			req: req
		})
	}
	return list
}